package com.culture.config.common.util;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import lombok.experimental.UtilityClass;

@UtilityClass
public class FunctionUtil {

    public String nonBlank(String str, Consumer<String> consumer){
        if(StringUtils.isBlank(str)){
            return null;
        }
        if(Objects.isNull(consumer)){
            return str;
        }
        consumer.accept(str);
        return str;
    }

    public String nonBlank(String [] items,int index, Consumer<String> consumer){
        if(ArrayUtils.isEmpty(items)){
            return null;
        }
        if(index < 0 || index >= items.length){
            return null;
        }
        if(StringUtils.isBlank(items[index])){
            return null;
        }
        if(Objects.isNull(consumer)){
            return items[index];
        }
        consumer.accept(items[index]);
        return items[index];
    }

    public <E> void ofEmpty(List<E> collection, Consumer<List<E>> consumer){
        if(CollectionUtils.isEmpty(collection)){
            return;
        }
        Optional.ofNullable(consumer).ifPresent(f->f.accept(collection));
    }

    public <E> void ofEmptyEach(List<E> collection, Consumer<E> consumer){
        if(CollectionUtils.isEmpty(collection)){
            return;
        }
        Optional.ofNullable(consumer).ifPresent(f->collection.forEach(f));
    }

    public <E> void ofEmptyFirst(List<E> collection, Consumer<E> consumer){
        if(CollectionUtils.isEmpty(collection)){
            return;
        }
        Optional.ofNullable(consumer).ifPresent(f->f.accept(collection.get(0)));
    }

    public void ofBlank(String text, Consumer<String> consumer){
        if(StringUtils.isBlank(text)){
            return;
        }
        Optional.ofNullable(consumer).ifPresent(f->f.accept(text));
    }

    public <T> void ofNull(T t, Consumer<T> consumer) {
        if(Objects.isNull(t)){
            return ;
        }
        Optional.ofNullable(consumer).ifPresent(f->f.accept(t));
    }

    public <T,K>  Map<K,List<T>> group(List<T> list, Function<? super T, ? extends K> classifier){
        if(CollectionUtils.isEmpty(list)){
            return Collections.emptyMap();
        }
        return list.stream().collect(Collectors.groupingBy(classifier));
    }

    public <T,R> List<R> map(List<T> list, Function<? super T, ? extends R> mapper){
        if(CollectionUtils.isEmpty(list)){
            return Collections.emptyList();
        }
        return list.stream().map(mapper).collect(Collectors.toList());
    }

    public <T,K> Map<K,T> toMap(List<T> list, Function<? super T, ? extends K> keyMapper){
        if(CollectionUtils.isEmpty(list)){
            return Collections.emptyMap();
        }
        return list.stream().collect(Collectors.toMap(keyMapper,Function.identity()));
    }

    public <T> List<T> filter(List<T> list, Predicate<? super T> predicate){
        if(CollectionUtils.isEmpty(list)){
            return Collections.emptyList();
        }
        List<T> results =  list.stream().filter(predicate).collect(Collectors.toList());
        return Optional.ofNullable(results).orElse(Collections.emptyList());
    }
   
    public static <E> List<E> sort(List<E> eList,Comparator<E> comparator){
        if(Objects.isNull(eList)){
            return Collections.emptyList();
        }
        if(Objects.isNull(comparator)){
            return eList;
        }
        return eList.stream().sorted(comparator).collect(Collectors.toList());
    }

    public static <R,E> List<R> mapListTo(List<E> dataList, Class<R> rClass){
        return mapListTo(dataList,rClass,null);
    }

    public static <R,E> List<R> mapListTo(List<E> dataList, Class<R> rClass, BiConsumer<E,R> func){
        return mapListTo(dataList,rClass,func,null);
    }

    public static <R,E> List<R> mapListTo(List<E> dataList, Class<R> rClass, BiConsumer<E,R> func, Comparator<R> comparator){
        if(Objects.isNull(dataList) || Objects.isNull(rClass)){
            return Collections.emptyList();
        }
        List<R> rList = dataList.stream().map(e->{
            R r = BeanUtil.copyProperties(e, rClass);
            Optional.ofNullable(func).ifPresent(f->f.accept(e,r));
            return r;
        }).collect(Collectors.toList());
        return sort(rList,comparator);
    }

    public <R> R batch(List<Long> ids, BiFunction<List<Long>,R,R> biFunction, int batchSize){
        R r = null;
        if(CollectionUtils.isEmpty(ids)){
            return r;
        }
        List<List<Long>> partitionIds = ListUtils.partition(ids,batchSize);
        for(List<Long> list:partitionIds ){
            r = biFunction.apply(list, r);
        }
        return r;
    }
    
}
